#include "TiffWriter.h"
#include "GDALCPP.h"
#include "OCMain/Log.h"
#include "OCMain/DataStream.h"
#include "OCMain/FileUtil.h"
#include "json/json.h"
#include "OCVolume/VolumeGridData.h"
#include "OCVolume/VolumeUtil.h"
#include "OCVolume/VolumeAlgorithm.h"

namespace OCPP
{
#define WGS84_SRS "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4326\"]]"
	using namespace Volume;

	bool gdalInitialized = false;
	TiffWriter::TiffWriter()
	{
		_typeExtension = "tiff";
		if (!gdalInitialized)
		{
			gdalInitialized = true;
			OGRRegisterAll();
		}
		poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
		assert(poDriver);
	}

	TiffWriter::~TiffWriter()
	{

	}

	bool TiffWriter::write(const VolumeGridData& ncGridData, const VolumeOptions& ncOptions)
	{
		setGZipCompress(false);
		const String outputPath = getOutputPath();

		String name = generateOutputName(ncGridData, ncOptions);

		String fileName = outputPath + "/" + name;

		if (_mkdirForFile)
		{
			FileUtil::makeDirectory(FileUtil::getFilePath(fileName));
		}

		const auto& extent = ncGridData.getExtent();
		float west = extent.xMin;
		float south = extent.yMin;
		float east = extent.xMax;
		float north = extent.yMax;

		int width = extent.dimX;
		int height = extent.dimY;

		GDALDataType dataType = ncGridData._dataType == VolumeGridData::Type_Char ? GDT_Byte : GDT_Float32;

		FloatVector data;
		for (const auto& val : ncGridData._vecDouble)
		{
			data.push_back((float)val);
		}

		int bands = 1;

		GDALDataset* poDataset = poDriver->Create(fileName.c_str(), width, height, bands, dataType, NULL);
		if (poDataset != NULL) {

			double adfGeoTransform[6] = {
				west,
				(east - west) / width, 0.0,
				north, 0.0,
				-(north - south) / height };
			poDataset->SetGeoTransform(adfGeoTransform);
			poDataset->SetProjection(WGS84_SRS);

			auto band = poDataset->GetRasterBand(1);
			void* dataPtr = ncGridData._dataType == VolumeGridData::Type_Double ?
				(char*)&data[0] : ncGridData._dataType == VolumeGridData::Type_Float ?
				(char*)&ncGridData._vecFloat[0] :
				(char*)&ncGridData._vecChar[0];

			band->RasterIO(GF_Write, 0, 0, width, height, dataPtr
				, width, height, dataType, 0, 0);

			GDALClose((GDALDatasetH)poDataset);
		}
		else {
			std::cerr << "Failed to create dataset." << std::endl;
		}

		return false;
	}

	void TiffWriter::test()
	{
		writeToFile("e:/test/output1.tif");
	}

	void TiffWriter::writeToFile(String fileName)
	{
		float west = -180.0;
		float south = -90.0;
		float east = 180.0;
		float north = 90.0;

		int width = 360;
		int height = 180;

		FloatVector data;
		data.resize(width * height * sizeof(float));

		int x = 0;
		for (auto& v : data)
		{
			v = x++;
		}

		GDALDataType dataType = GDT_Float32;
		int bands = 1;

		GDALDataset* poDataset = poDriver->Create(fileName.c_str(), width, height, bands, dataType, NULL);
		if (poDataset != NULL) {

			double adfGeoTransform[6] = {
				west,
				(east - west) / width, 0.0,
				north, 0.0,
				-(north - south) / height };
			poDataset->SetGeoTransform(adfGeoTransform);
			poDataset->SetProjection(WGS84_SRS);

			auto band = poDataset->GetRasterBand(1);

			band->RasterIO(GF_Write, 0, 0, width, height, &data[0], width, height, dataType, 0, 0);

			GDALClose((GDALDatasetH)poDataset);
		}
		else {
			std::cerr << "Failed to create dataset." << std::endl;
		}
	}
}